<?php

/*
 * db.inc
 * 
 * database handler
 *
 * Provide db() to handle all database requests.
 */

/*
 * how to use it:

    // create a database object, and connect, but already done!
    //$db = new Database();
		// use db() instead!!!

    // execute query without expecting result
    $result = $db->execute( 'INSERT ...' );

    // execute query and expecting result set
    $result = $db->select( 'SELECT ...' );

    // parse result
    while( ($row = $result->getNext()) ) {
        $field_a = $row['field_a'];
        $field_b = $row['field_b'];

        // alternative

        $field_a = $result->getVal( 'field_a' );
        $field_b = $result->getVal( 'field_b' );
    }

    // disconnect is done when $db is destroyed (automaticaly)
*/

/*
 * Database expect few defines:
 * DB_TYPE : specify type of database (mysql / pgsql)
 * DB_HOST : database hostname / ip address
 * DB_PORT : database port (null if default, integer otherwise)
 * DB_NAME : database name to connect to 
 * DB_USER : database username
 * DB_PASSWD : database password
 */

/*
 * Database object
 * main and generic handle for a database connection
 * it is dealing with a specific DBConnector (depending on database type), and provide a wrapper interface
 */
class Database {

    // current DBConnector object
    private $connector = null;

    /*
     * constructor
     */
    function Database() { self::__construct(); }
    function __construct()
    {
        $type = Conf::$c['db']['type'];

        if( $type == 'mysql' ) 
        {
            require_once( 'db_mysql.php' );
            $this->connector = new MySQL_DBConnector();
        } 
        elseif( $type == 'pgsql' )
        {
            require_once( 'db_pgsql.php' );
            $this->connector = new PgSQL_DBConnector();
        } 
        else
        {
            die( 'Database::Database: unknwon type of database ('.$type.') <br>'."\n" );
        }

        // connect
        if( !$this->connect( Conf::$c['db']['host'], Conf::$c['db']['port'], Conf::$c['db']['name'], Conf::$c['db']['user'], Conf::$c['db']['passwd'] ) )
        {
            $error = $this->connector->lastError();
            die( 'Database::Database: unable to connect to database (host:'.Conf::$c['db']['host'].':'.Conf::$c['db']['port'].' - database:'.Conf::$c['db']['name'].' - user:'.Conf::$c['db']['user'].'): error:'.$error.' <br>'."\n" );
        }
    }

    /*
     * destructor()
     */
    function __destruct() 
    {
        $this->disconnect();
    }

    /*
     * connect()
     * connect to database
     * params:
     *  - host: database host name
     *  - port: databse port number (null if default port should be used)
     *  - dbname: database name
     *  - user: username
     *  - password: password
     * return:
     *  - true if connection was successful
     *  - false if connection failed (set lastError())
     */
    function connect( $host, $port, $dbname, $user, $password )
    {
        return $this->connector->connect( $host, $port, $dbname, $user, $password );
    }

    /*
     * disconnect()
     */
    function disconnect()
    {
        return $this->connector->disconnect();
    }
		
		/*
		 * useDatabase()
		 * select given database
		 * params:
		 * 	- databaseName
		 * return:
		 * 	- true: ok
		 *	- false: pas ok
		 */
		function useDatabase( $dbName )
		{
			return $this->connector->useDatabase( $dbName );
		}

    /*
     * lastError()
     * return string with a description of the last error
     */
    function lastError()
    {
        return $this->connector->lastError();
    }

    /*
     * select()
     * execut a SQL request which return a result set (SELECT)
     * params:
     *  - sql: sql request to execute
     * return:
     *  - a DBResult object if execution went well
     *  - false if error (and set last error)
     */
    function select( $sql )
    {
        return $this->connector->select( $sql );
    }

    /*
     * execute()
     * execute a SQL request which doesn't return any result (INSERT, UPDATE, ALTER...etc.)
     * params:
     *  - sql: sql request to execute
     * return:
     *  - true; if execution went well
     *  - false: if error (and set last error)
     */
    function execute( $sql )
    {
        return $this->connector->execute( $sql );
    }

		/*
		 * lastId()
		 * return last id auto-incremented
		 * params:
		 * 	- table: tablename
		 *	- fieldname: fieldname
		 * return:
		 *	- id
		 */
		function lastId( $table, $fieldname )
		{
				return $this->connector->lastId( $table, $fieldname );
		}	

    /* 
     * escapeStr()
     * escape given string (handle special character to avoid sql error while execution)
     * params:
     *  - txt: text to escape
     * return:
     *  - escaped text
     */
    function escapeStr( $txt )
    {
        return $this->connector->escapeStr( $txt );
    }
}


/*
 * DBConnector
 * represent a database connector
 * it has to be overloaded (extended) to be database-type specialized
 */
class DBConnector {

    // current database connection
    var $conn = null;

    // string containing the last error
    var $lastError = '';

    /*
     * constructor
     */
    function DBConnector() { self::__construct(); }
    function __construct() 
    {
    }

    /*
     * destructor
     */
    function __destruct() 
    {
    }

    /* 
     * connect
     * connect to database
     * params:
     *  - host: database host name
     *  - port: databse port number (null if default port should be used)
     *  - dbname: database name
     *  - user: username
     *  - password: password
     * return:
     *  - true if connection was successful
     *  - false if connection failed (set lastError())
     */
    function connect( $host, $port, $dbname, $user, $password )
    {
        die( 'DBConnector::connect: you must overload DBConnector class!<br>' );
    }

    /*
     * disconnect
     * discconnect from current database
     */
    function disconnect()
    {
        die( 'DBConnector::disconnect: you must overload DBConnector class!<br>' );
    }

		/*
		 * useDatabase()
		 * select given database
		 */
		function useDatabase( $dbName )
		{
				die( 'DBConnector::useDatabase: you must overload DBConnector class!<br>' );
		}

    /*
     * lastError()
     * return a string of the last error
     */
    function lastError()
    {
        return $this->lastError;
    }

    /*
     * setLastError()
     * set last error
     * params:
     *  - error: string of the last error
     */
    function setLastError( $err )
    {
        $this->lastError = $err;
    }

    /*
     * execute()
     * execute a SQL request which doesn't return any result (INSERT, UPDATE, ALTER...etc.)
     * params:
     *  - sql: sql request to execute
     * return:
     *  - true; if execution went well
     *  - false: if error (and set last error)
     */
    function execute( $sql )
    {
        die( 'DBConnector::execute: you must overload DBConnector class!<br>' );
    }

    /*
     * select()
     * execut a SQL request which return a result set (SELECT)
     * params:
     *  - sql: sql request to execute
     * return:
     *  - a DBResult object if execution went well
     *  - false if error (and set last error)
     */
    function select( $sql )
    {
        die( 'DBConnector::select: you must overload DBConnector class!<br>' );
    }

		/*
		 * lastId()
		 * return last id auto-incremented
		 * params:
		 * 	- table: tablename
		 *	- fieldname: fieldname
		 * return:
		 *	- id
		 */
		function lastId( $table, $fieldname )
		{
				die( 'DBConnector::lastId: you must overload DBConnector class!<br>' );
		}	

    /* 
     * escapeStr()
     * escape given string (handle special character to avoid sql error while execution)
     * params:
     *  - txt: text to escape
     * return:
     *  - escaped text
     */
    function escapeStr( $txt )
    {
        die( 'DBConnector::escapeStr: you must overload DBConnector class!<br>' );
    }
}

/*
 * DBResult
 * object which represent a result set
 * it has to be overloaded (extended) to be database-type specialized
 */
class DBResult {

    // hold a reference to the database connector
    var $connector = null;

    // hold the result set
    var $resultSet = null;

    // hold the current row
    var $row = null;

    /*
     * constructor
     * params:
     *  - connector: specific database connector
     *  - resultset: result set
     * return: 
     *  - nothing: this is a constructor
     */
    function DBResult( &$connector, $resultset ) { self::__construct( &$connector, $resultset ); }
    function __construct( &$connector, $resultset )
    {
        $this->connector = &$connector;
        $this->resultSet = $resultset;
    }

    /*
     * destructor
     */
    function __destruct()
    {
    }

    /*
     * getNext()
     * select (and return) the next row in a result set
     * return:
     *  - false if no row in the result set
     *  - associative array of a row (indexed by field names)
     */
    function getNext()
    {
        die( 'DBResult::getNext: you must overload DBResult class!' );
    }

    /*
     * getVal()
     * return the value for given field name in current row
     * params:
     *  - fieldName: interesting field name
     * return:
     *  - return: value for given field name
     */
    function getVal( $fieldName )
    {
        if( is_null($this->row) )
        {
            // if row == null: we need to call getNext() to fetch the first row
            if( !$this->getNext() ) return null;
        }
        return $this->row[ $fieldName ];
    }

    /*
     * rowCount()
     * return the number of row in current result set
     */
    function rowCount()
    {
        die( 'DBResult::rowCount: you must overload DBResult class!' );
    }

    /*
     * columnCount()
     * return the number of column in current result set
     */
    function columnCount()
    {
        die( 'DBResult::columnCount: you must overload DBResult class!' );
    }

}

// global database instance
$_database = null;

// return database instance function
$_get_database_fct = "_db_create";

// return current global databse instance
function &_db_return()
{
	global $_database;
	return $_database;
}

// create current global database instance, and return it
function &_db_create()
{
	global $_database, $_get_database_fct;
	$_database = new Database();
	$_get_database_fct = "_db_return";
	return $_database;
}

// return global database instance, create it if not done yet
function &db()
{
	global $_get_database_fct;
	return $_get_database_fct();
}

?>
